Stream Player Control

您所在的位置:网站首页 wpf 播放视频流 Stream Player Control

Stream Player Control

2023-07-26 05:14| 来源: 网络整理| 查看: 265

原文地址: https://www.codeproject.com/articles/885869/stream-player-control 在本文中,您将会找到一个流播放器控件的实现。 Download WPF demo - 12.9 MBDownload WinForms demo - 12.6 MBDownload WPF source - 10.2 KBDownload WinForms source - 11.7 KBDownload FFmpeg Facade source - 17.8 KB 介绍 这篇文章是我前一篇文章的一个延续,它展示了一个网络摄像头控件的实现。 最近我创建了另一个控件,并希望与社区分享我的经验。 这是一个基于FFmpeg的流播放器控件,可以执行以下操作: 播放 RTSP/RTMP视频流或本地视频文件检索控件显示的当前帧该控件没有额外的依赖和一个简约的界面。

必要条件

该控件的WinForms版本是使用.NET Framework 2.0实现的该控件的WPF版本是使用.NET Framework 4 Client Profile实现的该控件支持x86和x64平台目标。

背景

现在通过互联网流式传输音频,视频和数据是非常平常的事情。 但是,当我试图找到一个.NET控件来播放通过网络发送的视频流时,我几乎找不到任何东西。 这个项目试图填补这个空白。

实现细节

如果你对实现细节不感兴趣,那么你可以跳过这一节。实施分为三层。

底层被实现为本地DLL模块,它将我们的调用转发给FFmpeg框架。为了便于分发,原生DLL模块作为资源嵌入到控件的程序集中。 在运行时阶段,DLL模块将被提取到磁盘上的临时文件,并通过后期绑定技术使用。 一旦控制权被处置,临时文件将被删除。 换句话说,该控件是作为一个单独的文件分发的。 所有这些操作都是由中间层来实现的。顶层实现控制类本身。下图显示了实现的逻辑结构。

只有顶层应该被客户使用。

底层

底层使用facade 模式来为FFmpeg框架提供一个简化的接口。 门面由三个类组成:StreamPlayer类,它实现了流播放功能

/// /// The StreamPlayer class implements a stream playback functionality. /// class StreamPlayer : private boost::noncopyable { public: /// /// Initializes a new instance of the StreamPlayer class. /// StreamPlayer(); /// /// Initializes the player. /// /// The StreamPlayerParams object that contains the information that is used to initialize the player. void Initialize(StreamPlayerParams playerParams); /// /// Asynchronously plays a stream. /// /// The url of a stream to play. void StartPlay(std::string const& streamUrl); /// /// Retrieves the current frame being displayed by the player. /// /// Address of a pointer to a byte that will receive the DIB. void GetCurrentFrame(uint8_t **bmpPtr); /// /// Retrieves the unstretched frame size, in pixels. /// /// A pointer to an int that will receive the width. /// A pointer to an int that will receive the height. void GetFrameSize(uint32_t *widthPtr, uint32_t *heightPtr); /// /// Uninitializes the player. /// void Uninitialize(); };Stream类将视频流转换为一系列帧

/// /// A Stream class converts a stream into series of frames. /// class Stream : private boost::noncopyable { public: /// /// Initializes a new instance of the Stream class. /// /// The url of a stream to decode. Stream(std::string const& streamUrl); /// /// Gets the next frame in the stream. /// /// The next frame in the stream. std::unique_ptr GetNextFrame(); /// /// Gets an interframe delay, in milliseconds. /// int32_t InterframeDelayInMilliseconds() const; /// /// Releases all resources used by the stream. /// ~Stream(); };Frame类,它是一组框架相关的工具。

/// /// The Frame class implements a set of frame-related utilities. /// class Frame : private boost::noncopyable { public: /// /// Initializes a new instance of the Frame class. /// Frame(uint32_t width, uint32_t height, AVPicture &avPicture); /// /// Gets the width, in pixels, of the frame. /// uint32_t Width() const { return width_; } /// /// Gets the height, in pixels, of the frame. /// uint32_t Height() const { return height_; } /// /// Draws the frame. /// /// A container window that frame should be drawn on. void Draw(HWND window); /// /// Converts the frame to a bitmap. /// /// Address of a pointer to a byte that will receive the DIB. void ToBmp(uint8_t **bmpPtr); /// /// Releases all resources used by the frame. /// ~Frame(); };这些树类是FFmpeg Facade DLL模块的核心。

中间层

中间层由StreamPlayerProxy类实现,该类用作FFmpeg Facade DLL模块的代理。首先,我们应该从资源中提取FFmpeg Facade DLL模块并将其保存到一个临时文件中。

_dllFile = Path.GetTempFileName(); using (FileStream stream = new FileStream(_dllFile, FileMode.Create, FileAccess.Write)) { using (BinaryWriter writer = new BinaryWriter(stream)) { writer.Write(Resources.StreamPlayer); } }然后我们将DLL模块加载到调用进程的地址空间中。

_hDll = LoadLibrary(_dllFile); if (_hDll == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error()); }并将DLL模块函数绑定到类实例方法。

private delegate Int32 StopDelegate(); private StopDelegate _stop; // ... IntPtr procPtr = GetProcAddress(_hDll, "Stop"); _stop = (StopDelegate)Marshal.GetDelegateForFunctionPointer(procPtr, typeof(StopDelegate));在处理控件时,我们卸载DLL模块并将其删除。

private void Dispose() { if (_hDll != IntPtr.Zero) { FreeLibrary(_hDll);   _hDll = IntPtr.Zero; } if (File.Exists(_dllFile)) { File.Delete(_dllFile); } }

顶层

顶层由具有以下接口的StreamPlayerControl类实现。

/// /// Asynchronously plays a stream. /// /// The url of a stream to play. /// An invalid string is passed as an argument. /// Failed to load the FFmpeg facade dll. /// Failed to play the stream. public void StartPlay(Uri uri) /// /// Retrieves the image being played. /// /// The current image. /// The control is not playing a video stream. /// Failed to get the current image. public Bitmap GetCurrentFrame(); /// /// Stops a stream. /// /// The control is not playing a stream. /// Failed to stop a stream. public void Stop(); /// /// Gets a value indicating whether the control is playing a video stream. /// public Boolean IsPlaying { get; } /// /// Gets the unstretched frame size, in pixels. /// public Size VideoSize { get; } /// /// Occurs when the first frame is read from a stream. /// public event EventHandler StreamStarted; /// /// Occurs when there are no more frames to read from a stream. /// public event EventHandler StreamStopped; /// /// Occurs when the player fails to play a stream. /// public event EventHandler StreamFailed; 使用

打开程序包管理器控制台,并将Nuget程序包添加到您的项目中:

Install-Package WebEye.Controls.WinForms.StreamPlayerControl首先,我们需要将控件添加到Visual Studio Designer工具箱,使用右键单击,然后选择“选择项目...”菜单项。 然后,我们将控件放置在所需的位置并具有所需的大小。 控件实例变量的默认名称将是streamPlayerControl1。 以下代码使用提供的地址异步播放流。

streamPlayerControl1.StartPlay(new Uri("rtsp://184.72.239.149/vod/mp4:BigBuckBunny_115k.mov"));

还有一个选项可以指定连接超时和底层传输协议。

streamPlayerControl1.StartPlay(new Uri("rtsp://184.72.239.149/vod/mp4:BigBuckBunny_115k.mov"), TimeSpan.FromSeconds(15), RtspTransport.UdpMulticast);要获得正在播放的帧,只需调用GetCurrentFrame()方法即可。 帧的分辨率和质量取决于流的质量。

using (Bitmap image = streamPlayerControl1.GetCurrentFrame()) { // image processing... }要停止流,使用Stop()方法。

streamPlayerControl1.Stop();您可以随时使用以下代码检查播放状态。

if (streamPlayerControl1.IsPlaying) { streamPlayerControl1.Stop(); }此外,StreamStarted,StreamStopped和StreamFailed事件可用于监视播放状态。 要报告错误,使用异常,所以不要忘记将代码包装在try / catch块中。 这就是使用它。 要查看完整的示例,请查看演示应用程序来源。

WPF版本

FFmpeg外观需要一个WinAPI窗口句柄(HWND)才能将其用作渲染目标。 问题是,在WPF世界的窗户不再有处理。 VideoWindow类解决了这个问题。

要将WPF版本的控件添加到项目中,请使用以下nuget命令:

Install-Package WebEye.Controls.Wpf.StreamPlayerControl

Github

该项目在下一页提供了一个GitHub仓库。https://github.com/jacobbo/WebEye/tree/master/StreamPlayerControl任何问题,评论和意见都是值得欢迎的。

外部许可

FFmpegfacade源与FFmpeg框架相同,在LGPL许可下获得许可。.NET控件的源代码和演示源在“代码项目开放许可证”(CPOL)下获得许可。您可以在您的商业产品中使用该控件,唯一的一点是您应该提及您的产品使用FFmpeg库,这里是详细信息。

历史 

March 19th, 2015 - The initial version.August 22nd, 2015 - Added the x64 platform support.October 25th, 2015 - Added asyncronous stream start and stream status events.November 8th, 2015 - Added support for local files playback.November 30th, 2015 - Added stream connection timeout.October 17th, 2017 - Use new FFmpeg decoding API. 本文许可本文以及任何相关的源代码和文件均已获得“ 代码项目开放许可证”(CPOL)的许可。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3